package cn.wolfcode.luowowo.service.impl;

import cn.wolfcode.luowowo.domain.Destination;
import cn.wolfcode.luowowo.domain.Strategy;
import cn.wolfcode.luowowo.domain.StrategyCatalog;
import cn.wolfcode.luowowo.domain.StrategyTheme;
import cn.wolfcode.luowowo.exception.LogicException;
import cn.wolfcode.luowowo.query.QueryObject;
import cn.wolfcode.luowowo.query.StrategyQuery;
import cn.wolfcode.luowowo.redis.vo.StrategyStatisVO;
import cn.wolfcode.luowowo.repository.StrategyRepository;
import cn.wolfcode.luowowo.service.IDestinationService;
import cn.wolfcode.luowowo.service.IStrategyCatalogService;
import cn.wolfcode.luowowo.service.IStrategyService;
import cn.wolfcode.luowowo.service.IStrategyThemeService;
import cn.wolfcode.luowowo.util.AssertUtil;
import cn.wolfcode.luowowo.util.DBHelper;
import com.sun.corba.se.impl.oa.toa.TOA;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;


import java.util.Date;
import java.util.List;
import java.util.Optional;

@Service
//@Transactional //事务最后处理
public class StrategyServiceImpl implements IStrategyService {

    @Autowired
    private StrategyRepository repository;

    @Autowired
    private MongoTemplate template;

    @Autowired
    private IStrategyCatalogService strategyCatalogService;

    @Autowired
    private IDestinationService destinationService;

    @Autowired
    private IStrategyThemeService strategyThemeService;

    @Autowired
    private IStrategyService strategyService;

    @Override
    public Strategy get(String id) {
        Optional<Strategy> optional = repository.findById(id);
        if (optional != null) {
            return optional.get();
        }
        return null;
    }

    @Override
    public Page<Strategy> query(StrategyQuery qo) {
        Query query = new Query();

        //通过目的地的 id 方式查询分页
        if (StringUtils.hasLength(qo.getDestId())) {
            query.addCriteria(Criteria.where("destId").is(qo.getDestId()));
        }

        //通过主题Id查询分页
        if (StringUtils.hasLength(qo.getThemeId())) {
            query.addCriteria(Criteria.where("themeId").is(qo.getThemeId()));
        }

        return DBHelper.query(template, Strategy.class, query, qo.getPageable());
    }


    @Override
    public void update(Strategy strategy) {
        //使用save方法是全量更新，如果更新部分，会出现未更新的字段被null覆盖
        //repository.save(strategy);

        //方案一：查询————替代————保存（效率低，用update）
        //方案二：显示使用update逻辑 update set...

        //条件对象
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(strategy.getId()));
        //使用工具简化更新的代码
        DBHelper.update(template, query, strategy,
                "destId", "destName", "themeId", "themeName", "catalogId", "catalogName"
                , "title", "subTitle", "summary", "coverUrl", "isabroad", "state", "content");

    }

    @Override
    public void save(Strategy strategy) {
        repository.save(strategy);
    }

    @Override
    public void delete(String id) {
        repository.deleteById(id);
    }

    @Override
    public List<Strategy> list() {
        List<Strategy> list = repository.findAll();
        return list;
    }

    //下架
    @Override
    public void changeState(String id) {
        //方案1：查询——修改——在保存
        //方案二：更新
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(id));
        Update update = new Update();
        update.set("state", "0");//状态改为0
        template.upsert(query, update, Strategy.class);
    }

    @Override
    public void saveOrUpdate(Strategy strategy) {
        //需要设置前台没有传过来的数据，否则保存的数据有空的情况

        //destId、destName目的地名称与id
        StrategyCatalog catalog = strategyCatalogService.get(strategy.getCatalogId());
        strategy.setDestId(catalog.getDestId());
        strategy.setDestName(catalog.getDestName());

        //themeName主题的名称
        StrategyTheme theme = strategyThemeService.get(strategy.getThemeId());
        strategy.setThemeName(theme.getName());

        //catalogName分类名称
        strategy.setCatalogName(catalog.getName());

        //isabroad是否国外
        //国内的isabroad是-1，要先获得吐司中是中国的，再将该攻略设置成国内
        List<Destination> toasts = destinationService.getToasts(catalog.getDestId());
        if (toasts != null && toasts.size() > 0) {//有跟才判断
            if ("中国".equals(toasts.get(0).getName())) {
                //分类的名字是中国的算国内
                strategy.setIsabroad(Strategy.ABROAD_NO);
            } else {
                strategy.setIsabroad(Strategy.ABROAD_YES);
            }
        }

        if (StringUtils.hasLength(strategy.getId())) {
            //编辑
            strategyService.update(strategy);
        } else {
            //添加，添加之前需要保存创建时间
            strategy.setCreateTime(new Date());
            strategy.setId(null);
            strategyService.save(strategy);
        }
    }

    //根据攻略分类的id查该分类下的所有的攻略文章
    @Override
    public List<Strategy> getByCatalogId(String catalogId) {
        List<Strategy> list = repository.findByCatalogId(catalogId);
        return list;
    }

    //根据目的地的id查询阅读量前三的攻略
    @Override
    public List<Strategy> getViewnumTop3(String destId) {
        //点击量前三
        PageRequest of = PageRequest.of(0, 3, Sort.Direction.DESC, "viewnum");

        return repository.findByDestId(destId, of);
    }

    //将Redis中的vo对象里的统计数据持久到mongodb中
    @Override
    public void updateStrategy(StrategyStatisVO vo) {
        Query query = new Query();
        //这里是为什么vo对象中定义StrategyId字段的原因
        query.addCriteria(Criteria.where("_id").is(vo.getStrategyId()));

        //vo是在Redis中的，MongoDB中是攻略，所以持久化就是将vo中对应攻略变化的数据保存起来
        //vo中的统计数据要封装进攻略里才能保存进mongodb，
        Strategy strategy = new Strategy();
        BeanUtils.copyProperties(vo,strategy );

        //更新攻略中设置好的统计数据
        DBHelper.update(template, query, strategy,
                "viewnum","replynum","favornum","sharenum","thumbsupnum");
    }

    //通过目的地名字查询攻略
    @Override
    public List<Strategy> findByDestName(String destName) {
        return repository.findByDestName(destName);
    }
}
